/*
 * 
 * Copyright 2010 David H Pollack
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 * 
 * 
 */

package com.dhpollack.rotogss.servlets;

import static com.google.appengine.api.labs.taskqueue.TaskOptions.Builder.url;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.regex.Pattern;

import javax.jdo.JDOObjectNotFoundException;
import javax.jdo.PersistenceManager;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;

import net.sf.jsr107cache.Cache;
import net.sf.jsr107cache.CacheException;
import net.sf.jsr107cache.CacheManager;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.dhpollack.rotogss.data.RotoGSSLeagueXml;
import com.dhpollack.rotogss.data.YahooGames;
import com.dhpollack.rotogss.data.YahooLeagueRosterPositions;
import com.dhpollack.rotogss.data.YahooLeagues;
import com.dhpollack.rotogss.helper.PMF;
import com.dhpollack.rotogss.helper.XPATH;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.labs.taskqueue.Queue;
import com.google.appengine.api.labs.taskqueue.QueueFactory;

/**
 * @author davidpl
 *
 */
public class YStoreLeagueServlet extends HttpServlet {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 7958740045481358567L;

	private String league;
	
	private Integer game;
	
	private static XPath xPath = XPATH.get().newXPath();
	
	protected void service(HttpServletRequest req, HttpServletResponse resp) 
    throws ServletException, IOException {
		
        Queue queue = QueueFactory.getDefaultQueue();

        league = req.getParameter("league");
		
		if(league == null) {
			log("No league set");
			return;
		} else {
			log("Processing stats for " + league);
		}
		
		boolean runQueue = (req.getParameter("runqueue") != null) ? true : false;
		
		// Processing for game key.  Will be replaced with game parse
		String regex = "\\.";
		Pattern numSplit = Pattern.compile(regex);
		String[] m = numSplit.split(league);
		game = Integer.parseInt(m[0]);
		
		RotoGSSLeagueXml xml = getLeagueXmlFromApp();
		
		//Date league_update = xml.getUpdateTimestamp();
		String league_xml = xml.getLeagueXml();
		
		NodeList league_node = parseLeagueXml(league_xml, "//league");
		int league_count = league_node.getLength(); // this should be 1, but I'm calculating it anyway
		for(int i=0; i < league_count; i++) {
			try {
				Key league_saved_key = saveLeagueToDatastore(league_node.item(i), false);
				if(runQueue) {
                    queue.add(url("/admin/yStoreStats").param("league", league).param("includeleague", "true"));
                    queue.add(url("/admin/yStoreTeams").param("league", league));
				}
				req.setAttribute(league + "-key", league_saved_key);
			} catch (NumberFormatException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (XPathExpressionException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
		
	}
	
	private RotoGSSLeagueXml getLeagueXmlFromApp() {
		// TODO Auto-generated method stub
		
        Cache cache = null;

        try {
            cache = CacheManager.getInstance().getCacheFactory().createCache(Collections.emptyMap());
        } catch (CacheException e) {
            // ...
        	log("Memcache creation failed");
        }
        
        String memcache_key = league + "-xml";
        RotoGSSLeagueXml xml = null;
        
        if(cache != null && cache.containsKey(memcache_key)) {
        	log("Using Memcache");
        	xml = (RotoGSSLeagueXml) cache.get(memcache_key);
        }
        if(xml == null) {
        	log("Using Datastore");
            PersistenceManager pm = PMF.get().getPersistenceManager();
            Key key = new KeyFactory.Builder(RotoGSSLeagueXml.class.getSimpleName(), league).getKey();
            try {
            	xml = pm.getObjectById(RotoGSSLeagueXml.class, key);
            } catch(JDOObjectNotFoundException e) {
            	log("LeagueXml not found in datastore");
            	e.printStackTrace();
            }
        }
		return xml;
	}

	private NodeList parseLeagueXml(String leagues_xml, String expression) {
		NodeList n = null;
		try {
			InputSource is = new InputSource(new StringReader(leagues_xml));
			Document response = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);
			n = (NodeList)xPath.evaluate( expression , response, XPathConstants.NODESET);
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (XPathExpressionException e) {
			e.printStackTrace();
		}
		return n;
	}
	
	private Key saveLeagueToDatastore(Node node, boolean force_update)
	throws NumberFormatException, XPathExpressionException {
		// TODO Auto-generated method stub
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Key key = new KeyFactory.Builder(YahooGames.class.getSimpleName(), game)
		 .addChild(YahooLeagues.class.getSimpleName(), league)
		 .getKey();
		YahooLeagues l;
		try {
			l = pm.getObjectById(YahooLeagues.class, key);
		} catch(JDOObjectNotFoundException e) {
			force_update = true;
			l = new YahooLeagues();
			l.setLeagueKey(key);
			l.setLeagueStats(new ArrayList<Key>());
			l.setGoogleUsers(new LinkedHashSet<Key>());
		}
		if(force_update) {
	    	Integer league_id 	= Integer.parseInt((String)xPath.evaluate("league_id", node, XPathConstants.STRING));
			String league_name = (String)xPath.evaluate("name", node, XPathConstants.STRING);
			String league_url = (String)xPath.evaluate("url", node, XPathConstants.STRING);
			String league_draft_status = (String)xPath.evaluate("draft_status", node, XPathConstants.STRING);
			Integer league_num_teams = Integer.parseInt((String)xPath.evaluate("num_teams", node, XPathConstants.STRING));
			String league_update_timestamp = (String)xPath.evaluate("league_update_timestamp", node, XPathConstants.STRING);
			Date d = new Date();
			d.setTime(Long.parseLong(league_update_timestamp) * 1000);
			String league_draft_type = (String)xPath.evaluate("//draft_type", node, XPathConstants.STRING);
			String league_scoring_type = (String)xPath.evaluate("//scoring_type", node, XPathConstants.STRING);
			Integer league_uses_playoff = Integer.parseInt((String)xPath.evaluate("//uses_playoff", node, XPathConstants.STRING));
			Integer league_uses_faab = Integer.parseInt((String)xPath.evaluate("//uses_faab", node, XPathConstants.STRING));
			
			Set<YahooLeagueRosterPositions> roster = saveRosterPositions(node);
			
			
			l.setLeagueId(league_id);
			l.setLeagueName(league_name);
			l.setLeagueUrl(league_url);
			l.setDraftStatus(league_draft_status);
			l.setNumTeams(league_num_teams);
			l.setLeagueUpdateTimestamp(d);
			l.setDraftType(league_draft_type);
			l.setScoringType(league_scoring_type);
			l.setUsesFaab(league_uses_faab);
			l.setUsesPlayoff(league_uses_playoff);
			l.setYahooLeagueRosterPositions(roster);
			
			try {
				pm.makePersistentAll(l);
			} finally {
				pm.close();
			}
		}
		if(!pm.isClosed()) {
			pm.close();
		}

		return key;

		
	}
	
	private Set<YahooLeagueRosterPositions> saveRosterPositions(Node node) throws XPathExpressionException {
		
    	NodeList roster_nodes = (NodeList)xPath.evaluate("settings/roster_positions/roster_position", node, XPathConstants.NODESET);
		int roster_count = roster_nodes.getLength();
		Set<YahooLeagueRosterPositions> rosterpositions = new LinkedHashSet<YahooLeagueRosterPositions>();
		for (int i=0; i < roster_count; i++) {
	    	//Get each xpath variable
			String roster_position = (String)xPath.evaluate("position", roster_nodes.item(i), XPathConstants.STRING);
			Integer roster_position_count = Integer.parseInt((String)xPath.evaluate("count", roster_nodes.item(i), XPathConstants.STRING));

			YahooLeagueRosterPositions r = new YahooLeagueRosterPositions();
			r.setRosterPosition(roster_position);
			r.setRosterPositionCount(roster_position_count);
			rosterpositions.add(r);
		}
		
		return rosterpositions;

	}



}
